﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SpeakupBackend;
using SpeakupBackend.Classes;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.Collections.Specialized;
using System.ComponentModel;
using WebLayer;

namespace Frontend
{
    enum TodoGridHeader {   Remove  = 0,
                            Time    = 2, 
                            Name    = 4,
                            Theme   = 6,
                            Status  = 8,
                            Action  = 10,
                            IsApplicable = 12};
    
    class TodoGrid: BorderedGrid
    {
        DelegateProxy<PropertyChangedEventHandler> PropertyChangedProxy =
                new DelegateProxy<PropertyChangedEventHandler>();

        DelegateProxy<NotifyCollectionChangedEventHandler> CollectionChangedProxy =
            new DelegateProxy<NotifyCollectionChangedEventHandler>();

        public TodoGrid()
        {
            CollectionChangedProxy.ProxySource += Classes_CollectionChanged;
            PropertyChangedProxy.ProxySource += Classes_PropertyChanged;

            SetupHeaders();
        }

        BackendContext m_backendCtx;
        public BackendContext BackendCtx
        {
            get
            {
                return m_backendCtx;
            }
            set
            {
                if (m_backendCtx != value)
                {
                    //unsubscribe from events from old backend ctx
                    if (m_backendCtx != null)
                    {
                        m_backendCtx.Classes.CollectionChanged -= CollectionChangedProxy.ProxyConsumer;
                        m_backendCtx.Classes.PropertyChanged -= PropertyChangedProxy.ProxyConsumer;
                    }

                    m_backendCtx = value;

                    //subscribe for class events
                    m_backendCtx.Classes.CollectionChanged += CollectionChangedProxy.ProxyConsumer;
                    m_backendCtx.Classes.PropertyChanged += PropertyChangedProxy.ProxyConsumer;

                    SetupGrid();
                }
            }
        }

        void Classes_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            Class cl = sender as Class;
            if (cl == null) return;

            if (cl.IsActionPending && !Entries.Keys.Contains(cl))
            {
                AddClass(cl);
            }
            else if (!cl.IsActionPending && Entries.Keys.Contains(cl))
            {
                RemoveClass(cl);
            }
        }

        void Classes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                if (e.NewItems != null)
                {
                    foreach (Class cl in e.NewItems)
                    {
                        if (cl.IsActionPending && !Entries.Keys.Contains(cl))
                        {
                            AddClass(cl);
                        }
                    }
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                if (e.OldItems != null)
                {
                    foreach (Class cl in e.NewItems)
                    {
                        if (Entries.Keys.Contains(cl))
                        {
                            RemoveClass(cl);
                        }
                    }

                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                foreach (Class cl in Entries.Keys.ToList())
                {
                    RemoveClass(cl);
                }
            }
        }

        Dictionary<Class, TodoGridEntry> Entries = new Dictionary<Class, TodoGridEntry>();

        void SetupGrid()
        {
            this.Entries.Clear();
            this.RowDefinitions.Clear();
            this.ColumnDefinitions.Clear();
            this.Children.Clear();

            SetupHeaders();

            foreach (Class cl in BackendCtx.Classes)
            {
                if (cl.IsActionPending)
                {
                    AddClass(cl);
                }
            }
        }

        void AddColumnHeader(TodoGridHeader header, string text, double proportion)
        {
            if (ColumnDefinitions.Count != (int)header)
            {
                throw new InvalidProgramException("Header with specified index can not be currenlty added.");
            }

            ColumnDefinition coldef = new ColumnDefinition();
            coldef.Width = new GridLength(proportion, GridUnitType.Star);
            ColumnDefinitions.Add(coldef);

            TextBlock block = new TextBlock();
            block.Inlines.Add(text);
            block.VerticalAlignment = VerticalAlignment.Center;
            block.TextWrapping = TextWrapping.Wrap;
            block.TextAlignment = TextAlignment.Center;
            block.Margin = new Thickness(5, 2, 5, 2);
            block.FontWeight = FontWeights.DemiBold;

            Grid.SetRow(block, 0);
            Grid.SetColumn(block, ColumnDefinitions.Count - 1);

            Children.Add(block);
        }
        void AddColumnSplitter()
        {
            ColumnDefinition coldef = new ColumnDefinition();
            coldef.Width = GridLength.Auto;
            ColumnDefinitions.Add(coldef);

            GridSplitter splitter = new GridSplitter();
            splitter.ResizeBehavior = GridResizeBehavior.PreviousAndNext;
            splitter.ResizeDirection = GridResizeDirection.Columns;
            splitter.ShowsPreview = true;

            splitter.Width = 1.5;
            splitter.Background = Brushes.Black;
            splitter.MouseMove += (e, s) => this.InvalidateVisual();

            Grid.SetColumn(splitter, ColumnDefinitions.Count - 1);
            Grid.SetRow(splitter, 0);
            Grid.SetRowSpan(splitter, Int32.MaxValue);

            Children.Add(splitter);
        }
        void SetupHeaders()
        {
            RowDefinition rowdef = new RowDefinition();
            rowdef.Height = GridLength.Auto;
            RowDefinitions.Add(rowdef);

            AddColumnHeader(TodoGridHeader.Remove, "", 0.5);
            AddColumnSplitter();
            AddColumnHeader(TodoGridHeader.Time, "Time", 0.5);
            AddColumnSplitter();
            AddColumnHeader(TodoGridHeader.Name, "Name", 1);
            AddColumnSplitter();
            AddColumnHeader(TodoGridHeader.Theme, "Theme", 1);
            AddColumnSplitter();
            AddColumnHeader(TodoGridHeader.Status, "Status", 0.5);
            AddColumnSplitter();
            AddColumnHeader(TodoGridHeader.Action, "Action", 0.5);
            AddColumnSplitter();
            AddColumnHeader(TodoGridHeader.IsApplicable, "Can this action be executed?", 1);

        }

        void AddClass(Class cl)
        {
            TodoGridEntry entry = new TodoGridEntry(cl);

            RowDefinition rowdef = new RowDefinition();
            rowdef.Height = GridLength.Auto;
            RowDefinitions.Add(rowdef);

            entry.AddToGrid(this, RowDefinitions.Count - 1);

            Entries.Add(cl, entry);
        }
        void RemoveClass(Class cl)
        {
            if (Entries.Keys.Contains(cl))
            {
                Entries[cl].RemoveFromGrid(this);
                Entries.Remove(cl);
            }
        }

    }
}
